/** 场景添加子节点附带参数 */
interface INodeParam {
    /** 需要添加的子节点对象 or Prefab对象 */
    node: cc.Node | cc.Prefab,
    /** 公共UI类型枚举 */
    uiType: yy.UIType | number,
    /** 父节点 (若父节点无效，则添加到当前场景) */
    parent?: cc.Node,
    /** 节点在父节点下的层级 (不传则默认当前的最高层级) */
    zIdx?: number
}

/**
 * Cocos Creator 场景组件相关拓展
 * 一些算法优化以提升性能
 */
export default class CanvasExt {

    /** 场景根节点 */
    static get canvasNode(): cc.Node {
        const scene = cc.director.getScene();
        if (!scene) {
            return null;
        }
        let canvas: cc.Node = scene.getChildByName("Canvas") || scene.getChildByName("canvas");
        if (!canvas) {
            for (const node of scene.children) {
                if (node.getComponent(cc.Canvas) != undefined) {
                    canvas = node;
                    break;
                }
            }
        }
        if (!canvas) canvas = scene;
        return canvas;
    }

    /** extern from cc.Node.on function */
    static on<T extends Function>(type: string, callback: T, target?: any, useCapture?: boolean): T {
        const canvas: cc.Node = this.canvasNode;
        if (canvas && canvas.isValid)
            return canvas.on(type, callback, target, useCapture);
        else
            return null;
    }

    /** extern from cc.Node.off function */
    static off(type: string, callback?: Function, target?: any, useCapture?: boolean): void {
        const canvas: cc.Node = this.canvasNode;
        if (canvas && canvas.isValid)
            canvas.off(type, callback, target, useCapture);
    }

    /**
     * 添加公用UI至当前场景
     * @param node 要添加的节点
     * @param uiType 公用UI类型
     * @param [zIdx] 节点在场景下层级
     * @returns cc.Node or null
     */
    static addChild(p: INodeParam): cc.Node {
        if (!p || !p.node || !p.node.isValid) return null;

        let node: cc.Node = null;
        if (p.node instanceof cc.Prefab) {
            node = cc.instantiate(p.node);
            if (!node) return null;
        }
        else
            node = p.node;

        let parent: cc.Node = p.parent;
        if (!parent || !parent.isValid)
            parent = this.canvasNode;

        const zIdx: number = p.zIdx == undefined ? this.getNodeTopZIdx(parent) : p.zIdx;
        node.attr({ uiType: p.uiType });
        parent.addChild(node, zIdx);
        return node;
    }

    /**
     * 查找指点节点（同名时返回层级最高节点）
     * @param typeOrName UIType 或 名称
     * @param parent 父节点
     * @returns cc.Node or null
     */
    static getNode(typeOrName: string | yy.UIType | number, parent?: cc.Node, deepLoop: boolean = false): cc.Node {
        if (!parent) parent = this.canvasNode;
        let func = null;
        if (typeof typeOrName == "string") {
            func = (n: cc.Node) => { return n.name == typeOrName; };
        } else {
            func = (n: cc.Node) => { return n["uiType"] == typeOrName; };
        }
        return this.findSceneNode(parent, func, deepLoop);
    }

    static hideNode(typeOrName: yy.UIType | string, parent?: cc.Node) {

    }

    // 查找当前节点下可见的子节点最高层级值，并返回+1值
    static getNodeTopZIdx(parent: cc.Node): number {
        let zIdx = 0;
        if (!!parent && parent.isValid) {
            const children = parent.children;
            if (children) {
                children.forEach((node: cc.Node) => {
                    if (!node || !node.isValid || !node.active) return;
                    const zId = node.zIndex;
                    // PROFILER-NODE节点zIndex为32767
                    if (zId != 32767 && zId > zIdx)
                        zIdx = zId + 1;
                });
            }
        }
        return zIdx;
    };

    // 查找场景下指定节点（包含未激活节点）
    private static findSceneNode(parent: cc.Node, func: (n: cc.Node) => boolean, deepLoop: boolean): cc.Node {
        if (!func) return null;
        const size = parent.childrenCount;
        const children = parent.children;
        if (!!parent && parent.isValid) {
            // 广度优先遍历
            for (let i = size - 1; i >= 0; i--) {
                const node = children[i];
                if (!!node && node.isValid) {
                    const ret: boolean = func(node);
                    if (ret) return node;
                }
            }
            // 递归
            if (deepLoop)
                for (const node of children) {
                    if (!!node && node.isValid)
                        return this.findSceneNode(node, func, true);
                }
        }
        return null;
    }

    /** 获取当前画布长宽比 */
    static getAspectRatio(): number {
        const frameSize = cc.view.getFrameSize();
        return frameSize.height / frameSize.width;
    }

}
